<template>
  <div class="base-form">
    <el-form :model="formData" ref="baseFormRef" v-bind="formAttrConfig">
      <el-row>
        <!-- 循环最好用template包裹 规范 -->
        <template v-for="item in formItems" :key="item">
          <el-col v-bind="colLayout" v-if="!item.isHidden">
            <el-form-item :label="item.label" :style="itemStyle" :rules="item.rules" :prop="item.field">
              <!-- 区分类型组件 -->
              <!-- input、password -->
              <template v-if="item.type === 'input' || item.type === 'password'">
                <el-input :show-password="item.type === 'password'" v-model="formData[`${item.field}`]"
                  @input="change($event, item.field)" v-bind="item.otherOptions"></el-input>
              </template>
              <!-- select -->
              <template v-else-if="item.type === 'select'">
                <el-select v-model="formData[`${item.field}`]" style="width: 100%" @change="change($event, item.field)"
                  v-bind="item.otherOptions">
                  <el-option v-for="option in item.options" :key="option.value" :value="option.value"
                    :label="option.label"></el-option>
                </el-select>
              </template>
              <!-- mutiSelect -->
              <template v-else-if="item.type === 'mutiSelect'">
                <el-select v-model="formData[`${item.field}`]" @change="change($event, item.field)"
                  v-bind="item.otherOptions" style="width: 100%" multiple>
                  <el-option v-for="option in item.options" :key="option.value" :value="option.value"
                    :label="option.label"></el-option>
                </el-select>
              </template>
              <!-- datePicker -->
              <template v-else-if="item.type === 'datepicker'">
                <el-date-picker v-model="formData[`${item.field}`]" style="width: 100%"
                  @change="change($event, item.field)" v-bind="item.otherOptions"></el-date-picker>
              </template>
              <!-- dateRange -->
              <template v-else-if="item.type === 'dateRange'">
                <el-date-picker v-model="formData[`${item.field}`]" v-bind="item.otherOptions" style="width: 100%"
                  @change="change($event, item.field)"></el-date-picker>
              </template>
              <!-- inputNumber -->
              <template v-else-if="item.type === 'inputNumber'">
                <el-input-number v-model="formData[`${item.field}`]" v-bind="item.otherOptions"
                  @input="change($event, item.field)" />
              </template>
              <!-- radio -->
              <template v-else-if="item.type === 'radio'">
                <el-radio-group v-model="formData[`${item.field}`]" @change="change($event, item.field)"
                  v-bind="item.otherOptions">
                  <el-radio :label="option.value" v-for="option in item.options">{{ option.label }}</el-radio>
                </el-radio-group>
              </template>
              <!-- tree select -->
              <template v-else-if="item.type === 'treeSelect'">
                <el-tree-select v-model="formData[`${item.field}`]" :data="item.options" v-bind="item.otherOptions"
                  @current-change="(data: any, node: any) => changeTree(data, node, item.field)" />
              </template>
              <!-- upload  avatar-->
              <template v-else-if="item.type === 'avatar'">
                <el-upload ref="uploadAvatarRef" v-bind="item.otherOptions" class="avatar-uploader"
                  :before-upload="uploadAvatarBeforeHook" :http-request="(config: any) => uploadAvatarHook(config, item.field)
                    ">
                  <img :src="SHOW_FILE + formData[`${item.field}`][0].name"
                    v-if="formData[`${item.field}`].length !== 0" class="avatar" />
                  <el-icon class="avatar-uploader-icon" v-else>
                    <Plus />
                  </el-icon>
                </el-upload>
              </template>
            </el-form-item>
          </el-col>
        </template>
        <div class="handle-slot" :style="itemStyle">
          <slot name="line-handle"></slot>
        </div>
      </el-row>
    </el-form>
  </div>
</template>

<script lang="js" setup>
import { ref, watch } from "vue";
import { Plus } from "@element-plus/icons-vue";
import { useUploadAvatar } from "@/old-hooks/use-upload-avatar";
import { SHOW_FILE } from "@/utils/url";

// 声明emit 提前定义方法
const emit = defineEmits(["update:formData", "change"]);

const props = defineProps({
  // 表单绑定值
  formData: {
    //组件之间双向绑定
    type: Object,
    required: true,
  },
  // 表单每一项配置
  formItems: {
    type: Array,
    default: () => ([]), // 数组、对象类型设置默认值 必须用 => 函数初始化
  },
  // 表单每一项样式
  itemStyle: {
    type: Object,
    default: () => ({ padding: "40px 40px" }),
  },
  // 表单栅格布局
  colLayout: {
    type: Object,
    default: () => ({
      xl: 6, // 24/6 >=1920 显示4个选项
      lg: 8, // 24/8
      md: 12, // 24/24
      sm: 24, // 24/24
      xs: 24, // 24/24
    }),
  },
  // 表单配置项
  formAttrConfig: {
    type: Object,
    default: () => ({ labelWidth: '100px', disabled: false }),
  }
});

// 表单数据
const formData = ref({});

// 监听组件之间formData 赋值给组件私有formData
watch(
  () => props.formData,
  (newValue) => {
    formData.value = props.formData;
    emit("update:formData", newValue);
  },
  {
    immediate: true,
    deep: true,
  }
);

// 表单dom
const baseFormRef = ref();

// 提交表单
const submitForm = (callBack) => {
  baseFormRef.value?.validate((valid, fields) => {
    if (valid) {
      callBack(valid);
    } else {
      // console.log("error submit!", fields);
    }
  });
};

// el-tree-change change事件
const changeTree = (data, node, field) => {
  let obj = {};
  obj.data = data;
  obj.node = node;
  change(obj, field);
};

// 组件change事件 处理表单联动 字段
const change = (event, field) => {
  emit("change", event, field);
};

// 上传头像回调
const uploadAvatarCallback = (res) => {
  formData.value[res.field] = [{ name: res.data[0].name }];
};

// 上传头像dom
const uploadAvatarRef = ref();

// 上传头像hook
const { uploadAvatarBeforeHook, uploadAvatarHook } = useUploadAvatar(
  uploadAvatarCallback
);

defineExpose({ submitForm });
</script>

<style lang="less" scoped>
.base-form {
  :deep(.el-form-item) {
    margin-bottom: 0;
  }

  .handle-slot {
    flex: 1;
    display: flex;
    justify-content: flex-end;
  }
}

.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}

.avatar-uploader {
  :deep(.el-upload) {
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
  }
}

.avatar-uploader {
  :deep(.el-upload:hover) {
    border-color: var(--el-color-primary);
  }
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>
